package com.tarena.shoot;
//步骤2引用
import java.awt.image.BufferedImage;
//步骤3引用：图片的读写
import javax.imageio.ImageIO;
//5.引入画图的两个类
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.xml.ws.handler.HandlerResolver;
//39.颜色类和字体类
import java.awt.Color;
import java.awt.Font;
//10.重写paint方法需要用到这个类
import java.awt.Graphics;
//30.鼠标事件类
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
//15.引入Random
import java.util.Random;
//16.引入定时器类和定时任务
import java.util.Timer;
import java.util.TimerTask;
//23.数组类
import java.util.Arrays;

/**主程序类*/
//6.继承JPanel
public class ShootGame extends JPanel{
	//1.窗口宽高
	public static final int WIDTH = 400;
	public static final int HEIGHT = 654;
	
	//2.项目所使用到的图片
	public static BufferedImage background;
	public static BufferedImage airplane;
	public static BufferedImage bee;
	public static BufferedImage bullet;
	public static BufferedImage gameover;
	public static BufferedImage hero0;
	public static BufferedImage hero1;
	public static BufferedImage pause;
	public static BufferedImage start;
	
	public static final int START = 0;
	public static final int RUNNING = 1;
	public static final int PAUSE = 2;
	public static final int GAME_OVER = 3;
	public int state = START;
	
	//8.new对象
	private Hero hero = new Hero();
	private FlyingObject[] flyings = {};
	private Bullet[] bullets = {};
		
	//3.给图片赋值(初始化静态资源)
	static {
		try {
			//4.
			background = ImageIO.read(ShootGame.class.getResource("background.png"));
			airplane = ImageIO.read(ShootGame.class.getResource("airplane.png"));
			bee = ImageIO.read(ShootGame.class.getResource("bee.png"));
			bullet = ImageIO.read(ShootGame.class.getResource("bullet.png"));
			gameover = ImageIO.read(ShootGame.class.getResource("gameover.png"));
			hero0 = ImageIO.read(ShootGame.class.getResource("hero0.png"));
			hero1 = ImageIO.read(ShootGame.class.getResource("hero1.png"));
			pause = ImageIO.read(ShootGame.class.getResource("pause.png"));
			start = ImageIO.read(ShootGame.class.getResource("start.png"));
		} catch (Exception e) {
			e.printStackTrace();		//处理异常
		}
	}
	
	/**14.把飞行机和蜜蜂按几率实例化*/
	public FlyingObject nextOne() {
		Random rand = new Random();
		int type = rand.nextInt(20);
		if(type < 2 ) {
			return new Bee();
		}else {
			return new Airplane();
		}  
	}
	
	//11.重写paint方法  g:画笔
 	public void paint(Graphics g) {
		//12.画各种对象
		g.drawImage(background,0,0,null);
		paintHero(g);
		paintFlyingObjects(g);
		paintBullets(g);
		//38.
		paintScoreAndLife(g);
		//44.
		paintSate(g);
	}
	//13.画的内容太多，1个方法对应1个对象
	public void paintHero(Graphics g) {
		g.drawImage(hero.image,hero.x,hero.y,null);
	}
	public void paintFlyingObjects(Graphics g) {
		for(int i = 0; i < flyings.length; i++) {
			FlyingObject f = flyings[i];
			g.drawImage(f.image,f.x,f.y,null);
		}
	}
	public void paintBullets(Graphics g) {
		for(int i = 0; i < bullets.length; i++) {
			FlyingObject b = bullets[i];
			g.drawImage(b.image,b.x,b.y,null);
		}
	}
	//37.画分和命
	public void paintScoreAndLife(Graphics g) {
		g.setColor(new Color(0xff0000));
							//字体                       加粗           大小 
		g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,24));
		g.drawString("score:" + score, 5, 20);
		g.drawString("life:" + hero.getLife(), 5, 40);
	}
	
	//43.画状态
	public void paintSate(Graphics g) {
		switch(state) {
		case START:
			g.drawImage(start,0,0,null);
			break;
		case PAUSE: 
			g.drawImage(pause, 0,0,null);
			break;
		case GAME_OVER:
			g.drawImage(gameover, 0,0,null);
			break;
		}
	}
		
	
	//22.辅助降低敌人出现频率的参数
	int flyEnteredIndex = 0;
	//20.敌人入场   生成敌人对象，把对象添加到flyings数组
	public void enterAction(){
		//21.时间限制，让敌人出现频率降低
		flyEnteredIndex++;
		if(flyEnteredIndex % 40 == 0) {  //每400毫秒出现1个敌人
			FlyingObject one = nextOne();
			flyings = Arrays.copyOf(flyings, flyings.length + 1);//扩容敌人数组长度
			flyings[flyings.length - 1] = one;		//把敌人对象放入数组最后一个位置
		}
	}
	
	//25.移动方法
	public void stepAction() {
		hero.step();
		for(int i = 0;i < flyings.length; i++) {
			flyings[i].step();
		}
		for(int i = 0;i < bullets.length; i++) {
			bullets[i].step();
		}
	}
	
	
	
	//28.子弹入场方法
	int shootIndex;
	public void shootAction() {	//10毫秒走一次
		//创建子弹对象，把对象放到bullets数组中
		shootIndex++;
		if(shootIndex % 30 == 0) {    //300毫秒发一次
			Bullet[] bs = hero.shoot();
			bullets = Arrays.copyOf(bullets, bullets.length + bs.length);   //子弹数组扩容
			System.arraycopy(bs, 0, bullets, bullets.length - bs.length, bs.length); //子弹数组追加
		}
	}
	
	//32.删除越界的对象
	public void outOfBoundsAction() {
		int index = 0;
		int index1 = 0;
		FlyingObject[] flyingLive = new FlyingObject[flyings.length];
		Bullet[] bulletLive = new Bullet[bullets.length];
		
		for(int i = 0; i < flyings.length; i++) {
			if(!flyings[i].outOfBounds()) {
				flyingLive[index] = flyings[i];
				index++;
			}
		}
		for(int j = 0; j < bullets.length;j++) {
			if(!bullets[j].outOfBounds()) {
				bulletLive[index1] = bullets[j];
				index1++;
			}
		}
		flyings = Arrays.copyOf(flyingLive, index);
		bullets = Arrays.copyOf(bulletLive, index1);
		
	}
	
	//34.碰撞方法
	public void bangAction() {
		for(int i =0; i < bullets.length;i++) {
			Bullet b = bullets[i];
			bang(b,i);
		}
	}
	//36.定义分
	int score = 0;
	//35.1个子弹与多个敌人碰撞
	public void bang(Bullet b,int num) {
		int index = -1;
		for(int i = 0; i < flyings.length; i++) {
			FlyingObject f = flyings[i];
			if(f.shootBy(b)) {
				index = i;
				Bullet bullet = bullets[num];
				bullets[num] = bullets[bullets.length -1];
				bullets[bullets.length -1] = bullet;
				bullets = Arrays.copyOf(bullets,bullets.length - 1);
				break;
			}
		}
		if(index != -1) {
			FlyingObject one = flyings[index]; //获取被撞敌人
			flyings[index] = flyings[flyings.length - 1];
			flyings[flyings.length - 1] = one;
			flyings = Arrays.copyOf(flyings,flyings.length - 1);
			if(one instanceof Enemy) {
				Enemy e = (Enemy)one;
				score += e.getScore();
			}
			if(one instanceof Award) {
				Award a = (Award)one;
				if(a.getType() == Award.DOUBLE_FIRE) {
					hero.addDoubleFire();
				}else {
					hero.addLife();
				}
			}
		}
	}
	
	//41.检查游戏结束
	public void checkGameOverAction() {
		if(isGameOver()) {
			state = GAME_OVER; //47.游戏结束
		}
	}
	
	//42.判断游戏是否结束
	public boolean isGameOver() {
		for(int i = 0; i < flyings.length; i++) {
			FlyingObject f = flyings[i];
			if(hero.hit(f)) {
				hero.subLife();
				hero.clearDoubleFire();
				flyings[i] = flyings[flyings.length - 1];
				flyings[flyings.length - 1] = f;
				flyings = Arrays.copyOf(flyings, flyings.length - 1);
			}
		}
		return hero.getLife() == 0;
	}
	
	//18.定义启动函数
	public void action() {
		//29.鼠标事件
		MouseAdapter l = new MouseAdapter() {
			
			public void mouseMoved(MouseEvent e) {
				if(state == RUNNING) {
					int x = e.getX();
					int y = e.getY();
					hero.moveTo(x, y);
				}
			}
			//49.鼠标移出
			public void mouseExited(MouseEvent e) {
				if(state != START) {
					state = RUNNING;
				}
				
			}
			//50.鼠标移入
			public void mouseEntered(MouseEvent e) {
				if(state != START) {
					state = RUNNING;
				}
			}
			//46.鼠标点击状态
			public void mouseClicked(MouseEvent e) {
				switch(state) {
				case START:
					state = RUNNING;
					break;
				case GAME_OVER:
					//48.重新开始，数据还原
					score = 0;
					hero = new Hero();
					flyings = new FlyingObject[0];
					bullets = new Bullet[0];
					state = START;
					break;
				}
			}
			
		};
		//侦听
		this.addMouseListener(l);		//处理鼠标操作事件
		this.addMouseMotionListener(l);	//处理鼠标的滑动 事件
		//19.定时器
		Timer timer = new Timer();
		int interval = 10;		//间隔10毫秒
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				if(state == RUNNING) {	//45.运行状态
					enterAction();  //敌人入场
					//24.移动
					stepAction();
					//27.子弹入场
					shootAction();
					//31.删除越界的敌人和子弹
					outOfBoundsAction();
					//33.碰撞
					bangAction();
					//40.英雄机与敌人碰撞
					checkGameOverAction();
				}
				//26.调用repaint重新画
				repaint();
			}
		}, interval,interval);
	}
	
	public static void main(String[] args) {
		//7.设置窗口属性
		JFrame frame = new JFrame("Fly");	//窗口
		ShootGame game = new ShootGame();	//面板
		frame.add(game);					//面板添加到窗口
		frame.setSize(WIDTH,HEIGHT);		//设置窗口代销
		frame.setAlwaysOnTop(true);			//设置窗口置顶
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);	//设置窗口关闭则进程关闭
		frame.setLocationRelativeTo(null);	//窗口相对位置默认0.0  设置后在屏幕中间
		frame.setVisible(true);				//设置窗口可见  2.尽快调用paint()方法
		
		//17.启动程序的执行
		game.action();
	}
}
